#include "kfifo_sp.h"
#include "c_mem.h"

#ifndef min
#define min(x,y) ((x)<(y)?(x):(y))
#endif

/*****************************************
*函数声明
*****************************************/
static void kfifo_copy_in(struct __kfifo *fifo, const void *src, TYPE_LEN len, TYPE_LEN off);
TYPE_LEN __kfifo_out_peek(struct __kfifo *fifo, void *buf, TYPE_LEN len);

#if 0
static inline TYPE_LEN roundup_pow_of_two(TYPE_LEN v);
static TYPE_LEN rounddown_pow_of_two(TYPE_LEN n);
#endif

/*******************************************************************
函数名称：cfifo_unused
函数原型：static inline TYPE_LEN cfifo_unused(struct __kfifo *fifo)
功能描述：计算fifo中未使用的元素数量
输入1   ：缓冲区结构体指针
返回值  ：fifo中未使用的元素数量
补充信息：无  
*********************************************************************/

static inline TYPE_LEN kfifo_unused(struct __kfifo *fifo)
{
	return (fifo->mask + 1) - (fifo->in - fifo->out);
}

/*******************************************************************
FIFO 使用的数量
*********************************************************************/

TYPE_LEN __kfifo_used(struct __kfifo *fifo) 
{
    return (fifo->in - fifo->out); 
}


/*******************************************************************
函数名称：__kfifo_in
函数原型：TYPE_LEN cfifo_in(struct __kfifo *fifo,const void *buf, TYPE_LEN len)
功能描述：向数据缓冲区写入多个数据
输入1   ：缓冲区结构体指针
输入2   ：数据指针
输入3   ：读取数据个数
返回值  ：读取成功个数
补充信息：无  
*********************************************************************/
TYPE_LEN __kfifo_in(struct __kfifo *fifo, const void *buf, TYPE_LEN len)
{
	TYPE_LEN l;

	l = kfifo_unused(fifo);
	if (len > l)
		len = l;

	kfifo_copy_in(fifo, buf, len, fifo->in);
	fifo->in += len;
	return len;
}

/*******************************************************************
函数名称：__kfifo_out
函数原型：TYPE_LEN cfifo_out(struct __kfifo *fifo, void *buf, TYPE_LEN len)
功能描述：向数据缓冲区写入多个数据
输入1   ：缓冲区结构体指针
输入2   ：数据指针
输入3   ：读取数据个数
返回值  ：读取成功个数
补充信息：无  
*********************************************************************/
TYPE_LEN __kfifo_out(struct __kfifo *fifo, void *buf, TYPE_LEN len)
{
	len = __kfifo_out_peek(fifo, buf, len);
	fifo->out += len;
	return len;
}

/**********************************************
 * FIFO输入 内部函数
 **********************************************/
static void kfifo_copy_in(struct __kfifo *fifo, const void *src, TYPE_LEN len, TYPE_LEN off)
{
	TYPE_LEN size = fifo->mask + 1;
	TYPE_LEN esize = fifo->esize;
	TYPE_LEN l;

	off &= fifo->mask;
	if (esize != 1) {
		off *= esize;
		size *= esize;
		len *= esize;
	}
	l = min(len, size - off);

	c_memcpy(fifo->data + off, src, l);
	c_memcpy(fifo->data, src + l, len - l);
	/*
	 * make sure that the data in the fifo is up to date before
	 * incrementing the fifo->in index counter
	 */
}


/**************************************************
 *  FIFO输出  内部函数
 ****************************************************/
static void kfifo_copy_out(struct __kfifo *fifo, void *dst, TYPE_LEN len, TYPE_LEN off)
{
	TYPE_LEN size = fifo->mask + 1;
	TYPE_LEN esize = fifo->esize;
	TYPE_LEN l;

	off &= fifo->mask;
	if (esize != 1) {
		off *= esize;
		size *= esize;
		len *= esize;
	}
	l = min(len, size - off);

	c_memcpy(dst, fifo->data + off, l);
	c_memcpy(dst + l, fifo->data, len - l);
	/*
	 * make sure that the data is copied before
	 * incrementing the fifo->out index counter
	 */
}

TYPE_LEN __kfifo_out_peek(struct __kfifo *fifo, void *buf, TYPE_LEN len)
{
	TYPE_LEN l;

	l = fifo->in - fifo->out;
	if (len > l)
		len = l;

	kfifo_copy_out(fifo, buf, len, fifo->out);
	return len;
}

#if 0 

//求不小于V的最大的2的幂指数 
//https://stackoverflow.com/questions/4398711/round-to-the-nearest-power-of-two
static inline TYPE_LEN roundup_pow_of_two(TYPE_LEN v) {
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v;
}


//求不大于n的最大的2的幂指数 
// https://blog.csdn.net/dreamispossible/article/details/91162847
static TYPE_LEN rounddown_pow_of_two(TYPE_LEN n) {
	n|=n>>1; 
    n|=n>>2; 
    n|=n>>4; 
    n|=n>>8; 
    n|=n>>16;
	return (n+1) >> 1;
}
#endif



